package com.yxuan.springboot.controller;


import cn.hutool.core.lang.UUID;
import com.alibaba.fastjson.JSONObject;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import com.yxuan.springboot.CustomizedException.DefaultException;
import com.yxuan.springboot.WxPayUtil.*;
import com.yxuan.springboot.WxPayUtil.SearchOrder.WxPayRefundUtil;
import com.yxuan.springboot.WxPayUtil.SearchOrder.WxPaySearchOrderUtil;
import com.yxuan.springboot.constant.config.WxPayConfig;
import com.yxuan.springboot.model.Goods;
import com.yxuan.springboot.model.Orders;
import com.yxuan.springboot.model.UserLogin;
import com.yxuan.springboot.model.UserVip;
import com.yxuan.springboot.service.*;
import com.yxuan.springboot.util.ResolveTokenUtil;
import com.yxuan.springboot.util.Result;
import com.yxuan.springboot.util.WxPayUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;


import static com.yxuan.springboot.util.Code.SUCCESSCODE;

@Slf4j
@Controller
@Api(tags = "微信支付")
@RequestMapping("/WxPay")
public class WxPayController {


    @Autowired
    private UserLoginService userLoginService;

    @Autowired
    private WxPayConfig wxPayConfig;

    @Autowired
    private Verifier verifier;

    @Autowired
    private CloseableHttpClient wxPayClient;

    @Autowired
    private OrdersService ordersService;

    @Autowired
    private UserVipService userVipService;

    @Autowired
    private WxPayUtil wxPayUtil;

    private String APP_SECRET = "8457a376f542b38eb62a22f403f77862";

    @Autowired
    private GoodsService goodsService;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 2.获取access_token
     * 在用户同意授权后，微信会回调预设的回调链接地址，并返回一个code参数。可以通过以下接口获取access_token和openid等信息：
     */
    @ResponseBody
    @RequestMapping("/wxforOpenid")
    public Result wxCallback(String code) throws Exception {

        Map<String, String> map = new HashMap<>();


        log.info("code:" + code);
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + wxPayConfig.getAppid() + "&secret=" + APP_SECRET + "&code=" + code + "&grant_type=authorization_code";
        String result = HttpUtils.sendGet(url);
        JSONObject jsonObject = JSONObject.parseObject(result);
        log.info("获取到的微信登录回调结果" + jsonObject.toJSONString());
        String accessToken = jsonObject.getString("access_token");
        String openId = jsonObject.getString("openid");
        map.put("openid",openId);

        return new Result(map, SUCCESSCODE, "返回openid成功");

    }




    @ApiOperation("小程序支付根据订单返回prepay_id参数")
    @ResponseBody
    @RequestMapping("/JSApiPayForPrepayid")
    public Result JSApiPay(HttpServletRequest request, @RequestParam String orderId) throws Exception {

        UserLogin userLogin = ResolveTokenUtil.targetLogin(request.getHeader("token"));
        UserLogin targetUserLogin = userLoginService.findObjectByPramas(userLogin);

        //根据订单号查询订单信息，给基础数据设置基础值
        Orders orders = new Orders();
        orders.setUserLoginId(targetUserLogin.getId().toString());
        orders.setOrderId(orderId);
        Orders targetOrder = ordersService.findObjectByPramas(orders);

        WeChatBasePayData weChatBasePayData = new WeChatBasePayData();
        weChatBasePayData.setTitle(targetOrder.getName());
        weChatBasePayData.setOrderId(targetOrder.getOrderId());
//        String total = targetOrder.getTotal();
//        int i = Integer.parseInt(total);
        weChatBasePayData.setPrice(targetOrder.getTotal());
        weChatBasePayData.setNotify(WxNotifyType.JSAPI_NOTIFY);
        HashMap<String, Object> map = new HashMap<>();
        log.info("接收pre");
        String prepay_id = WxPayCommon.wxJsApiPay(wxPayConfig, weChatBasePayData, targetUserLogin.getOpenId(), wxPayClient);
        map.put("package","prepay_id="+prepay_id);
        //时间戳
        long timestamp = System.currentTimeMillis()/1000;
        //随机串
        String nonceStr = java.util.UUID.randomUUID().toString().replace("-","");
        String pck = "prepay_id="+prepay_id;
        System.out.println("=================================");
        System.out.println(wxPayConfig.getAppid());
        System.out.println(timestamp);
        System.out.println(nonceStr);
        System.out.println(pck);
        System.out.println("=================================");



        String pckSign = wxPayUtil.getSign(wxPayConfig.getAppid(),timestamp,nonceStr,pck);
        System.out.println(pckSign);
        System.out.println("=================================");


        String time = String.valueOf(timestamp);
        map.put("timestamp",time);
        map.put("nonceStr",nonceStr);
        map.put("signType","RSA");
        map.put("paySign",pckSign);
        map.put("appid",wxPayConfig.getAppid());
        map.put("partnerid",wxPayConfig.getMchId());


        return new Result(map, SUCCESSCODE, "订单请求发送成功");
    }




    @ApiOperation("APP支付根据订单返回prepay_id参数")
    @RequestMapping("/AppPayForPrepayid")
    public Result AppPay(HttpServletRequest request,@RequestParam String orderId) throws Exception {

        UserLogin userLogin = ResolveTokenUtil.targetLogin(request.getHeader("token"));
        UserLogin targetUserLogin = userLoginService.findObjectByPramas(userLogin);

        //根据订单号查询订单信息，给基础数据设置基础值
        Orders orders = new Orders();
        orders.setUserLoginId(targetUserLogin.getId().toString());
        orders.setOrderId(orderId);
        Orders targetOrder = ordersService.findObjectByPramas(orders);

        WeChatBasePayData weChatBasePayData = new WeChatBasePayData();
        weChatBasePayData.setTitle(targetOrder.getName());
        weChatBasePayData.setOrderId(targetOrder.getOrderId());
//        String total = targetOrder.getTotal();
//        int i = Integer.parseInt(total);
        weChatBasePayData.setPrice(targetOrder.getTotal());
        weChatBasePayData.setNotify(WxNotifyType.APP_NOTIFY);


        String prepay_id = WxPayCommon.wxAppPay(wxPayConfig, weChatBasePayData, wxPayClient);
        HashMap<String, Object> map = new HashMap<>();
        map.put("prepayid",prepay_id);



        return new Result(map,SUCCESSCODE,"APP支付成功");
    }





//    @ApiOperation("微信支付回调接口")
//    @PostMapping("/wx/callback")
//    public String courseNative(HttpServletRequest request, HttpServletResponse response) throws DefaultException {
//        return WxPayCallbackUtil.wxPaySuccessCallback(request, response, verifier, wxPayConfig, callbackData -> {
//            // TODO 处理你的业务逻辑，下面说一下一般业务逻辑处理方法
//            log.info("微信支付回调返回的信息：{}", callbackData);
//            // 1.根据订单id获取订单信息
//            String orderId = callbackData.getOrderId();
//            String tradestate = callbackData.getTradestate();
//            // 2.判断金额是否相符，如果不相符则调用退款接口，并取消该订单，通知客户支付金额不符
//
//            // 3.查询订单状态是否是未支付，如果是未支付则改为已支付，填充其他逻辑，
//            if ("SUCCESS".equals(tradestate)) {
//                //支付成功，你的业务逻辑
//                log.info("支付成功");
//
//
//                // 交换机名称
//                String exchange = "wxzhifu.exchange";
//                // 发送消息
//                rabbitTemplate.convertAndSend(exchange,"wx", orderId);
//
//
////                //将订单状态改成已支付
////                Orders order = new Orders();
////                order.setOrderId(orderId);
////                order.setOrdersState("1");
////                try {
////                    //修改订单支付状态
////                    ordersService.upd(order);
////
////                    //根据orderid找到userid锁定用户
////                    Orders targetOrder = ordersService.findObjectByPramas(order);
////                    String userId = targetOrder.getUserLoginId();
////
////                    //修改用户vip表里的数据
////                    UserVip userVip = new UserVip();
////                    userVip.setUserId(Integer.valueOf(userId));
////
////                    log.info("goodsName为:"+targetOrder.getName());
////                    Result result = userVipService.updateVipByPay(Integer.valueOf(userId), targetOrder.getName());
//
//
//                //查询订单状态是否已支付，若已支付则跳过
////                Orders orders = new Orders();
////                orders.setOrderId(orderId);
////                orders.setOrdersState("1");
////                Orders objectByPramas = null;
////                try {
////                    objectByPramas = ordersService.findObjectByPramas(orders);
////                } catch (Exception e) {
////                    e.printStackTrace();
////                }
////                if (objectByPramas == null){
////
////                    try {
////
////
////                        //        修改订单状态
////                        ordersService.upd(orders);
////
////                        Orders targetOrder = ordersService.findObjectByPramas(orders);
////                        Orders orders1 = ordersService.findObjectByPramas(orders);
//////      搜索该商品的名称
////                        Goods goods = new Goods();
////                        goods.setId(Integer.valueOf(orders1.getGoodsId()));
////                        Goods goods1 = goodsService.findObjectByPramas(goods);
////
////                        UserVip userVip = new UserVip();
////                        userVip.setUserId(Integer.valueOf(targetOrder.getUserLoginId()));
////                        UserVip userVip1 = userVipService.findObjectByPramas(userVip);
////                        String vipRankMyself = userVip1.getVipRank();
////                        Integer getGptTimes = 0;
////                        if (userVip1.getGptTimes() == null || userVip1.getGptTimes().equals("")) {
////                            getGptTimes = 0;
////                        } else {
////                            getGptTimes = Integer.valueOf(userVip1.getGptTimes());
////                        }
////
////                        Integer getInfoUpdTimes = 0;
////                        if (userVip1.getInfoUpdTimes() == null || userVip1.getInfoUpdTimes().equals("")) {
////                            getInfoUpdTimes = 0;
////                        } else {
////                            getInfoUpdTimes = Integer.valueOf(userVip1.getInfoUpdTimes());
////                        }
////
////                        Integer getProbabilityTimes = 0;
////                        if (userVip1.getProbabilityTimes() == null || userVip1.getProbabilityTimes().equals("")) {
////                            getProbabilityTimes = 0;
////                        } else {
////                            getProbabilityTimes = Integer.valueOf(userVip1.getProbabilityTimes());
////                        }
////                        switch (goods1.getName()) {
////                            case "日会员":
////                                userVip.setVipRank("1");
////                                userVip.setProbabilityTimes(String.valueOf(getProbabilityTimes + 50));
////                                userVip.setInfoUpdTimes(String.valueOf(getInfoUpdTimes + 2));
////                                userVip.setGptTimes(String.valueOf(getGptTimes + 5));
////                                break;
////                            case "周会员":
////                                userVip.setVipRank("2");
////                                userVip.setProbabilityTimes(String.valueOf(getProbabilityTimes + 50));
////                                userVip.setInfoUpdTimes(String.valueOf(getInfoUpdTimes + 3));
////                                userVip.setGptTimes(String.valueOf(getGptTimes + 50));
////                                break;
////                            case "月会员":
////                                userVip.setVipRank("3");
////                                userVip.setProbabilityTimes(String.valueOf(getProbabilityTimes + 50));
////                                userVip.setInfoUpdTimes(String.valueOf(getInfoUpdTimes + 5));
////                                userVip.setGptTimes(String.valueOf(getGptTimes + 120));
////                                break;
////                            default:
////                                userVip.setVipRank("1");
////                                userVip.setProbabilityTimes(String.valueOf(getProbabilityTimes + 50));
////                                userVip.setInfoUpdTimes(String.valueOf(getInfoUpdTimes + 2));
////                                userVip.setGptTimes(String.valueOf(getGptTimes + 5));
////                                break;
////                        }
////
////                        if(Integer.parseInt(userVip.getVipRank()) < Integer.parseInt(vipRankMyself)) {
////                            userVip.setVipRank(vipRankMyself);
////                        }
////
////                        Date nows = new Date(System.currentTimeMillis());
////
////                        if (userVip1.getExpirationTime() == null || userVip1.getExpirationTime().compareTo(nows) < 0) {
////                            LocalDateTime now = LocalDateTime.now();
////                            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
////                            String formattedNow = now.format(formatter);
////                            System.out.println("当前时间：" + formattedNow);
////                            LocalDateTime after10Minutes = null;
////                            if (goods1.getName().equals("日会员")) {
////                                after10Minutes = now.plusMinutes(60 * 24);
////
////                            } else if (goods1.getName().equals("周会员")) {
////                                after10Minutes = now.plusMinutes(60 * 24 * 7);
////
////                            } else if (goods1.getName().equals("月会员")) {
////                                after10Minutes = now.plusMinutes(60 * 24 * 30);
////
////                            } else {
////                                after10Minutes = now.plusMinutes(60 * 24);
////
////                            }
////                            String formattedAfter10Minutes = after10Minutes.format(formatter);
////                            Date expirationTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(formattedAfter10Minutes);
////                            userVip.setExpirationTime(expirationTime);
////                        } else {
////                            Date date = userVip1.getExpirationTime();
////
////                            // 使用Calendar类将date转换为Calendar对象
////                            Calendar calendar = Calendar.getInstance();
////                            calendar.setTime(date);
////
////                            // 在Calendar对象上增加24小时
////
////
////                            if (goods1.getName().equals("日会员")) {
////                                calendar.add(Calendar.HOUR_OF_DAY, 24);
////                            } else if (goods1.getName().equals("周会员")) {
////                                calendar.add(Calendar.HOUR_OF_DAY, 24 * 7);
////                            } else if (goods1.getName().equals("月会员")) {
////                                calendar.add(Calendar.HOUR_OF_DAY, 24 * 31);
////                            } else {
////                                calendar.add(Calendar.HOUR_OF_DAY, 24);
////                            }
////                            // 将Calendar对象转换为Date对象
////                            Date newDate = calendar.getTime();
////
////                            // 使用DateTimeFormatter类将Date对象格式化为指定格式的字符串
////                            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
////                            String formattedNewDate = LocalDateTime.ofInstant(newDate.toInstant(), ZoneId.systemDefault()).format(formatter);
////                            // 使用SimpleDateFormat类将字符串转换为Date对象
////                            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
////                            Date expirationTime = null;
////                            try {
////                                expirationTime = sdf.parse(formattedNewDate);
////                            } catch (Exception e) {
////                                e.printStackTrace();
////                            }
////                            System.out.println(expirationTime + "===================");
////
////                            // 调用setExpirationTime方法
////                            userVip.setExpirationTime(expirationTime);
////                            System.out.println(formattedNewDate);
////
////                        }
////                        userVipService.upd(userVip);
////                        UserVip userVip2 = new UserVip();
////                        userVip2.setUserId(Integer.valueOf(targetOrder.getUserLoginId()));
////                        userVipService.findObjectByPramas(userVip2);
////
////                    } catch (Exception e) {
////                        e.printStackTrace();
////                    }
////            }
//
//
//            }
//
//
//
//
//        });
//    }

    @ApiOperation("微信支付回调接口")
    @PostMapping("/wx/callback")
    public String courseNative(HttpServletRequest request, HttpServletResponse response) throws DefaultException {
        return WxPayCallbackUtil.wxPaySuccessCallback(request, response, verifier, wxPayConfig, callbackData -> {
            // TODO 处理你的业务逻辑，下面说一下一般业务逻辑处理方法
            log.info("微信支付回调返回的信息：{}", callbackData);
            // 1.根据订单id获取订单信息
            String orderId = callbackData.getOrderId();
            String tradestate = callbackData.getTradestate();
            // 2.判断金额是否相符，如果不相符则调用退款接口，并取消该订单，通知客户支付金额不符

            // 3.查询订单状态是否是未支付，如果是未支付则改为已支付，填充其他逻辑，
            if ("SUCCESS".equals(tradestate)) {
                //支付成功，你的业务逻辑
                log.info("支付成功");

                // 交换机名称
                String exchange = "wxzhifu.exchange";
                // 发送消息
                rabbitTemplate.convertAndSend(exchange,"wx", orderId);


            }




        });
    }

    /**
     * 支付完成后前端传微信订单号或商户订单号查询订单支付状态，根据返回值来更新前端页面显示的支付状态，根据返回值里的tradestate字段看状态
     */


    @ApiOperation("根据微信订单号查询订单")
    @PostMapping("/search/order/transaction/{transactionId}")
    public WxchatCallbackSuccessData searchByTransactionId(@PathVariable String transactionId) throws DefaultException {
        return WxPaySearchOrderUtil.searchByTransactionId(wxPayConfig, transactionId, wxPayClient);
    }

    @ApiOperation("根据商户订单号查询")
    @ResponseBody
    @PostMapping("/search/order")
    public Result searchByOrderId(@RequestBody Map<String, String> mp) throws DefaultException {
        log.info(mp.get("orderId"));
        Map<String, Object> map = new HashMap<>();
        WxchatCallbackSuccessData wxchatCallbackSuccessData = WxPaySearchOrderUtil.searchByOrderId(wxPayConfig, mp.get("orderId"), wxPayClient);
        map.put("orderState",wxchatCallbackSuccessData.getTradestate());

        return new Result(map,SUCCESSCODE,"查询订单状态成功");
    }


    /**
     * 申请退款
     * 当交易发生之后一年内，由于买家或者卖家的原因需要退款时，卖家可以通过退款接口将支付金额退还给买家，微信支付将在收到退款请求并且验证成功之后，将支付款按原路退还至买家账号上。
     *
     * @param orderId
     * @return
     * @throws DefaultException
     */
    @ApiOperation("退款申请测试")
    @GetMapping("/refund/{orderId}")
    public String refund(@PathVariable String orderId) throws DefaultException {
        WeChatRefundParam param = new WeChatRefundParam();
        param.setOrderId(orderId);
        //要先生成并存储商户退款单号，注意写给方法自定义！
        // String refundOrderId = IdWorker.getIdStr();
        // log.info("refundOrderId:{}",refundOrderId);
        // param.setRefundOrderId(refundOrderId);
        UUID uuid = UUID.fastUUID();
        param.setReason("商品售罄");
        param.setNotify(WxNotifyType.REFUND_NOTIFY);
        param.setRefundMoney(new BigDecimal("0.01"));
        param.setTotalMoney(new BigDecimal("0.01"));

        //存储订单的退款单号


        return WxPayRefundUtil.refundPay(wxPayConfig, param, wxPayClient);
    }

    /**
     * 微信退款回调方法
     *
     * @param request
     * @param response
     * @return
     * @throws DefaultException
     */
    @ApiOperation("微信退款回调接口")
    @PostMapping("/wx/refund/callback")
    public String refundWechatCallback(HttpServletRequest request, HttpServletResponse response) throws DefaultException {
        return WxPayCallbackUtil.wxPayRefundCallback(request, response, verifier, wxPayConfig, new WechatRefundCallback() {
            @Override
            public void success(WxchatCallbackRefundData refundData) {
                // TODO 退款成功的业务逻辑，例如更改订单状态为退款成功等
            }

            @Override
            public void fail(WxchatCallbackRefundData refundData) {
                // TODO 特殊情况下退款失败业务处理，例如银行卡冻结需要人工退款，此时可以邮件或短信提醒管理员，并携带退款单号等关键信息
            }
        });
    }


}
